package logic;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.util.Random;


public class ThreadMDB extends Thread {
	public static char CR = '\r';
	public static char LF = '\n';
	private Server server;
	public ThreadMDB(Server server)
	{
		this.setServer(server);
	}
	public void run(){

		byte[] sendData = new byte[65000];

		while(true){

			try {
				byte[] receiveData = new byte[65000];
				DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);

				server.getMDB_socket().receive(receivePacket);
				String message_received = new String( receivePacket.getData(),0,receivePacket.getLength());
				String[] mensagem=new String[10];
				int indexFinalHeader = message_received.indexOf("\r\n\r\n");
				if(indexFinalHeader == -1)
				{
					System.out.println(receivePacket.getAddress().toString());
				}
				else if(indexFinalHeader != -1)
				{	
					String header = message_received.substring(0, indexFinalHeader);
					mensagem=header.split(" ");

					Chunk ch=null;

					if((mensagem[0].equals("PUTCHUNK") && (mensagem[1].equals(Server.defautVersion) || mensagem[1].equals(Server.VERSION)))){
						LogMensage lm=new LogMensage("RECEIVED PUTCHUNK -  HOST: " + receivePacket.getAddress().getHostName()+ " FileID: "+mensagem[2] + " Chunk number: "+ mensagem[3]);
						Server.logMensagesStr.insertElementAt(lm.str(), 0);
					}

					if(mensagem[0].equals("PUTCHUNK") &&mensagem[1].equals(Server.defautVersion) && !Server.enhancement){
						PutchunkMessage pMessage=new PutchunkMessage(mensagem[2],Integer.parseInt(mensagem[3]));//adiciona a lista de putchunks para ter um 'historico'
						if(!server.getPutchunkBlackList().contains(pMessage))
						{
							boolean find=false;
							for(int i=0;i<Server.getChunkRepository().getChunks().size();i++){
								Chunk chunk= Server.getChunkRepository().getChunks().elementAt(i);
								if(chunk.getFileID().equals(mensagem[2]) && chunk.getChunkNo()== Integer.parseInt(mensagem[3]) )
								{
									find=true;
									ch=chunk;
									break;
								}
							}
							boolean save=true;
							if(!find)
							{
								ch=new Chunk(mensagem[2],Integer.parseInt(mensagem[3]),Integer.parseInt(mensagem[4]));

								Server.getChunkRepository().addChunk(ch);
								int contentStart=message_received.indexOf("\r\n\r\n")+4;
								if(indexFinalHeader == -1)
								{
									System.out.println(receivePacket.getAddress().toString());
								}
								else if(indexFinalHeader != -1)
								{
									String content=message_received.substring(contentStart, message_received.length());
									long actSize=Server.getChunkRepository().getRepositorySpaceOccupied();
									actSize+=content.getBytes().length;
									if(actSize>Server.getChunkRepository().getRepositorySize())
									{
										save=false;
										System.out.println("Disk full!");
									}
									else
									{
										Server.getChunkRepository().setRepositorySpaceOccupied(actSize);

										byte[] cont=new byte[receivePacket.getLength()-(indexFinalHeader+4)];
										for(int i=0;i<receivePacket.getLength()-(indexFinalHeader+4);i++)
										{
											cont[i]=receivePacket.getData()[indexFinalHeader+4+i];
										}

										FileOutputStream  out = new FileOutputStream (new File(mensagem[2]+mensagem[3]));

										out.write(cont);
										out.close(); 
									}
								}

							}
							if(save)
							{
								String reply = new String("STORED "+Server.defautVersion+" "+mensagem[2]+" "+mensagem[3]+" "+CR+LF+CR+LF);
								sendData=reply.getBytes();
								DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, server.getMC_address(), server.getMC_port());
								Random randomGenerator = new Random();
								long random = randomGenerator.nextInt(Server.delay);
								sleep(random);
								LogMensage lm=new LogMensage("SEND STORED - "+"HOST: " + " FileID: "+mensagem[2] + " Chunk number: "+ mensagem[3]);
								Server.logMensagesStr.insertElementAt(lm.str(),0);
								server.getMC_socket().send(sendPacket);
								sleep(Server.delay - random); //para garantir que todos ja enviaram os storeds ou seja o tempo 0-400ms ja acabou
							}
							ch.addIP("localhost");//adiciona o seu proprio ip a lista de ips
							for(int j=0;j<server.getStoredMessages().size();j++)
							{
								if(server.getStoredMessages().get(j).getChunkNo()== ch.getChunkNo() 
										&& server.getStoredMessages().get(j).getFileID().equals(ch.getFileID()))
								{
									if(!ch.getIps().contains(server.getStoredMessages().get(j).getIp()))//verifica se ja tem aquele ip
									{
										ch.getIps().add(server.getStoredMessages().get(j).getIp());
										server.getStoredMessages().remove(j);
										j--;

									}
								}
							}
						}
						Server.getChunkRepository().saveInFile(Server.CHUNKS);

					}
					else if(mensagem[0].equals("PUTCHUNK")&&mensagem[1].equals(Server.defautVersion) && Server.enhancement)
					{
						PutchunkMessage pMessage=new PutchunkMessage(mensagem[2],Integer.parseInt(mensagem[3]));//adiciona a lista de putchunks para ter um 'historico'

						if(!server.getPutchunkBlackList().contains(pMessage))//verifica se o putchunk nao se refere a um chunk removido recentemente
						{
							boolean find=false;
							Chunk chunkTmp = new Chunk(mensagem[2], Integer.parseInt(mensagem[3]));

							if(Server.getChunkRepository().getChunks().contains(chunkTmp));
							{
								int index = Server.getChunkRepository().getChunks().indexOf(chunkTmp);
								if(index!=-1){
									ch = Server.getChunkRepository().getChunks().elementAt(index);
									find=true;
								}
							}
							boolean save=true;
							if(!find)
							{
								ch=new Chunk(mensagem[2],Integer.parseInt(mensagem[3]),Integer.parseInt(mensagem[4]));

								int contentStart=message_received.indexOf("\r\n\r\n")+4;
								if(indexFinalHeader == -1)
								{
									System.out.println(message_received);
									System.out.println(receivePacket.getAddress().toString());
								}
								else if(indexFinalHeader != -1)
								{
									String content=message_received.substring(contentStart, message_received.length());
									long actSize=Server.getChunkRepository().getRepositorySpaceOccupied();
									actSize+=content.getBytes().length;

									if(actSize>Server.getChunkRepository().getRepositorySize())
									{
										save=false;
										LogMensage lm=new LogMensage("INFO - DISK FULL");
										Server.logMensagesStr.insertElementAt(lm.str(),0);
									}


									Random randomGenerator = new Random();
									long random = randomGenerator.nextInt(Server.delay);
									sleep(random);

									for(int j=0;j<server.getStoredMessages().size();j++)
									{
										if(server.getStoredMessages().get(j).getChunkNo()== ch.getChunkNo() 
												&& server.getStoredMessages().get(j).getFileID().equals(ch.getFileID()))
										{
											if(!ch.getIps().contains(server.getStoredMessages().get(j).getIp()))//verifica se ja tem aquele ip
											{
												ch.getIps().add(server.getStoredMessages().get(j).getIp());
												server.getStoredMessages().remove(j);
												j--;

											}
										}
									}
									if(save && ch.getIps().size()<ch.getReplicationDeg())
									{
										Server.getChunkRepository().setRepositorySpaceOccupied(actSize);
										byte[] cont=new byte[receivePacket.getLength()-(indexFinalHeader+4)];
										for(int i=0;i<receivePacket.getLength()-(indexFinalHeader+4);i++)
										{
											cont[i]=receivePacket.getData()[indexFinalHeader+4+i];
										}

										FileOutputStream  out = new FileOutputStream (new File(mensagem[2]+mensagem[3]));

										out.write(cont);
										out.close(); 

										String reply = new String("STORED "+Server.defautVersion+" "+mensagem[2]+" "+mensagem[3]+" "+CR+LF+CR+LF);
										sendData=reply.getBytes();
										DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, server.getMC_address(), server.getMC_port());
										LogMensage lm=new LogMensage("SEND STORED - "+"HOST: " + " FileID: "+mensagem[2] + " Chunk number: "+ mensagem[3]);
										Server.logMensagesStr.insertElementAt(lm.str(),0);

										server.getMC_socket().send(sendPacket);

										Server.getChunkRepository().addChunk(ch);
										ch.addIP("localhost");//adiciona o seu proprio ip a lista de ips

									}
								}		

							}
							else if(find)
							{
								Random randomGenerator = new Random();
								long random = randomGenerator.nextInt(Server.delay);
								sleep(random);

								for(int j=0;j<server.getStoredMessages().size();j++)
								{
									if(server.getStoredMessages().get(j).getChunkNo()== ch.getChunkNo() 
											&& server.getStoredMessages().get(j).getFileID().equals(ch.getFileID()))
									{
										if(!ch.getIps().contains(server.getStoredMessages().get(j).getIp()))//verifica se ja tem aquele ip
										{
											ch.getIps().add(server.getStoredMessages().get(j).getIp());
											server.getStoredMessages().remove(j);
											j--;

										}
									}
								}

								String reply = new String("STORED "+Server.defautVersion+" "+mensagem[2]+" "+mensagem[3]+" "+CR+LF+CR+LF);
								sendData=reply.getBytes();
								DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, server.getMC_address(), server.getMC_port());
								LogMensage lm=new LogMensage("SEND STORED - "+"HOST: " + " FileID: "+mensagem[2] + " Chunk number: "+ mensagem[3]);
								Server.logMensagesStr.insertElementAt(lm.str(),0);
								server.getMC_socket().send(sendPacket);
							}




						}

						Server.getChunkRepository().saveInFile(Server.CHUNKS);
					}
				}

			} catch (IOException e) {

			} catch (InterruptedException e) {

			}


		}
	}
	public Server getServer() {
		return server;
	}
	public void setServer(Server server) {
		this.server = server;
	}
}
